/**
* SPORE core v1.1
* @fileoverview: 实现JS命名空间的管理，模块的定义，与自动加载依赖模块的脚本文件。
* @author: Esoul | pillar0514@gmail.com
*	@web: http://code.google.com/p/mootools-doc-cn/
*/

(function () {

	// #region -- Private Fields --

	var undefined, 								//防止全局污染
			that = {}, 								//当前命名空间
			jsParent = null, 					//用于插入script节点的父节点。
			doc = document, 					//变量引用速度更快
			JSManager = {}, 					//要暴露出的JS管理器
			RequireCache = [], 				//模块需求列表缓存
			ExecuteQueue = [], 				//模块执行队列
			RequireList = [], 				//总模块需求列表
			ModuleCache = {}, 				//模块缓存
			JSRequested = {}, 				//已请求过的JS模块
			RequireTree = {}, 				//模块需求多叉树
			Traversed = {}, 					//遍历缓存
			ModuleLoaded = [], 				//已经加载的模块的名字列表（用于调试）
			RequireHash = {}, 				//模块需求列表的位置索引
			isCoreAllLoaded = false,  //mootools.core是否已经预先载入
			isMoreAllLoaded = false;  //mootools.more是否已经预先载入

	// #endregion

	// #region -- Private Methods --

	/**
	* @method checkDepend 检查模块依赖文件是否已请求
	* @param {String} mName 模块名称
	*/
	var checkDepend = function (mName) {
		var requires = [].concat(RequireCache);
		RequireCache.length = 0;
		RequireTree[mName] = requires;
		$each(requires, function (name) {
			if (!JSRequested[name]) {
				ExecuteQueue.unshift(name);
				RequireHash[name] = RequireList.length;
				RequireList.push(name);
				loadModule(name);
				JSRequested[name] = true;
			}
		});
		checkReady();
	};

	/**
	* @method checkReady 检查依赖列表中的模块文件是否都已就绪。
	* @desc 如果都就绪了，就开始进行遍历（假定队列中的每个模块都是顶节点，进行多叉树深度遍历）。
	*/
	var checkReady = function () {
		if (!RequireList.join('')) {
			$each(ExecuteQueue.reverse(), traverse);
			ExecuteQueue.length = 0;
			RequireList.length = 0;
			RequireHash = {};
		}
	};

	/**
	* @method traverse 深度遍历模块引用多叉树，设置模块加载成功
	* @param {String} name 节点名称
	*/
	var traverse = function (name) {
		if (!name || Traversed[name]) { return; } //确保每个节点只能访问一次（避免循环引用造成的死锁）
		Traversed[name] = true; 				//事实上一个初始化模块，必定只允许运行一次
		$each(RequireTree[name], traverse);
		setModuleReady(name);
	};

	/**
	* @method setModuleCache 设置模块加载成功
	* @param {String} mName 模块的名称
	*/
	var setModuleReady = function (mName) {
		if (ModuleCache[mName] === 'ready') { return; }
		var nsParent,
				ns = that,
				arrName = (mName || '').split('.');
		$each(arrName, function (name) {
			nsParent = ns;
			ns = ns[name] = ns[name] || {};
		});
		nsParent[arrName.pop()] = ModuleCache[mName].call(null, that) || {};
		ModuleCache[mName] = 'ready';
		ModuleLoaded.push(mName);
	};

	/**
	* @method loadModule 加载一个模块
	* @param {String} mName 模块的名称
	*/
	var loadModule = function (mName) {
		loadjs((JSManager.$basepath || '') + mName.split('.').join('/') + '.js?version=' + JSManager.$version);
	};

	/**
	* @method loadjs 加载一个JS文件
	* @param {String} strsrc JS文件的地址
	*/
	var loadjs = function (strsrc) {
		var js = doc.createElement('script');
		js.type = 'text/javascript';
		js.charset = JSManager.$charset;
		js.src = strsrc;
		if (!jsParent) { jsParent = doc.getElementsByTagName('head')[0]; }
		jsParent.appendChild(js);
	};

	/**
	* @method each 遍历一个对象
	* @param {Object} obj 可遍历的对象
	* @param {Function} fn 要操作的函数
	* @param {Object} bind 遍历函数要绑定的对象
	*/
	var $each = function (obj, fn, bind) {
		for (var key in obj) {
			if (obj.hasOwnProperty(key)) {
				fn.call(bind, obj[key], key, obj);
			}
		}
	};

	/**
	* @method register 注册一个模块
	* @param {String} mName 模块的名称
	* @param {Function} maker 模块构造函数
	*/
	var register = function (mName, maker) {
		if (!(isCoreAllLoaded && name.slice(0, 5) === "core.") && !(isMoreAllLoaded && name.slice(0, 5) === "more.")) {
			if (ModuleCache[mName]) {
				throw ('The "' + mName + '" has been registered!!!');
			}
			ModuleCache[mName] = maker;
			if (!JSRequested[mName]) {
				ExecuteQueue.push(mName);
				JSRequested[mName] = true;
			}
			if (RequireHash[mName] !== undefined) {
				RequireList[RequireHash[mName]] = '';
			}
			checkDepend(mName);
		}
	};

	/**
	* @method $Import 加载（引入）一个模块
	* @param {String} name 模块的名称
	*/
	var $Import = function (name) {
		if (!(isCoreAllLoaded && name.slice(0, 5) === "core.") && !(isMoreAllLoaded && name.slice(0, 5) === "more.")) {
			RequireCache.push(name);
		}
	};

	// #endregion

	// #region -- 参数配置区 --

	var spaceName = 'HmJS'; 						 //定义顶层命名空间的名称
	var managerName = '$JSManager'; 		 //要暴露出去的JS管理器的名称
	var regName = 'register'; 					 //要暴露出去的注册组件函数的名称
	var impName = '$Import'; 						 //要暴露出去的引用组件函数的名称
	JSManager.$basepath = 'src/'; 			 //JS库所在的线上路径
	JSManager.$charset = 'utf-8'; 			 //JS文件的编码	
	JSManager.$version = new Date() - 0; //JS版本号

	// #endregion

	// #region -- 适配器 --

	that[impName] = $Import;
	that[regName] = register;
	that[managerName] = JSManager;

	that.$ImportCoreAll = function () {
		$Import('core.all');
		isCoreAllLoaded = true;
	};
	that.$ImportMoreAll = function () {
		$Import('core.all');
		$Import('more.all');
		isCoreAllLoaded = true;
		isMoreAllLoaded = true;
	};
	that.version = '1.0.1.0';
	that.website = 'http://www.cutesprite.com';

	ModuleCache[impName] = ModuleCache[regName] = ModuleCache[managerName] = 'ready';
	JSManager.$ModuleCache = ModuleCache;
	JSManager.$RequireList = RequireList;
	JSManager.$ModuleLoaded = ModuleLoaded;
	if (!this[spaceName]) {
		this[spaceName] = that;
	} else {
		$each(that, function (prop, name) {
			if (!this[spaceName][name]) {
				this[spaceName][name] = prop;
			} else {
				throw ('Lib "' + spaceName + '" exists the same prop: ' + name);
			}
		});
		that = this[spaceName];
	}

	// #endregion

})();